package com.sefer.dragonfly.client.core.container;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import javax.management.MBeanOperationInfo;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.sefer.dragonfly.client.confige.MonitorConfige;
import com.sefer.dragonfly.client.core.cache.CmCache;
import com.sefer.dragonfly.client.core.cache.CmCacheMuster;
import com.sefer.dragonfly.client.core.cache.DefaultCmCacheMuster;
import com.sefer.dragonfly.client.core.domain.CmConsumer;
import com.sefer.dragonfly.client.core.domain.CmConsumerChain;
import com.sefer.dragonfly.client.core.domain.lifecycle.BaseLifecycle;
import com.sefer.dragonfly.client.core.domain.mbean.annotation.CMbean;
import com.sefer.dragonfly.client.core.domain.mbean.annotation.CMbeanMethod;
import com.sefer.dragonfly.client.core.exception.DragonFlyException;
import com.sefer.dragonfly.client.core.thread.JobScheduler;
import com.sefer.dragonfly.client.utils.MBeanAnnotationRegister;

/**
 * <pre>
 * 监控容器，负责管理插件，缓存的生命周期
 * 
 * 缓冲区规则:
 * 采集到的数据再次缓存后，由plugin读取数据
 * 
 * 插件的缓存区时独立的，根据配置，插件可以分配到固定大小的缓存，根据插件ID区分
 * 提供默认缓冲区，由扫描器插件写入日志文件。
 * 
 * 注意： 为了兼容出错情况，如果ID重复，会自动加上类名来区分，
 * 如果还不区分则会抛出运行时异常，该异常会在启动时获得，可能会引起应用启动失败
 * 
 * 插件规则：
 * 插件负责做真正的事情，负责记录日志或者与服务端交互，插件是一些定时运行的任务。
 * 
 * 
 * </pre>
 * 
 * @see CmConsumer
 * @see CmCache
 */
@CMbean
public class MonitorContainer extends BaseLifecycle {

	private static final Logger logger = Logger
			.getLogger(MonitorContainer.class);

	private volatile static MonitorContainer container = null;
	private JobScheduler jobScheduler;
	private CmConsumerChain pluginChain = null;
	private CmCacheMuster<String, Serializable> cacheMuster;

	private MonitorContainer() {
		super();
	}

	/**
	 * 初始化所有的插件
	 */
	@Override
	public void init() {
		super.init();
		synchronized (MonitorContainer.class) {
			if (container == null) {
				container = new MonitorContainer();
			}
			if (jobScheduler == null) {
				jobScheduler = new JobScheduler();
			}
			if (cacheMuster == null) {
				cacheMuster = new DefaultCmCacheMuster();
			}
			if (pluginChain == null) {
				pluginChain = new CmConsumerChain();
			}
		}

		jobScheduler.init();

		MonitorConfige confige = new MonitorConfige();
		// 配置缓存区和所有的插件
		confige.buildMonitorConfige(cacheMuster, pluginChain);

		// 初始化插件
		for (CmConsumer plugin : pluginChain.getCmConsumers()) {
			plugin.init();
			try {
				// 把插件注册到定时器中
				jobScheduler.registerPlugin(plugin);
			} catch (Exception e) {
				logger.error(
						MessageFormat.format("Plugin init exception , {0}",
								e.getMessage()), e);
				// continue next
			}
		}
	}

	/**
	 * 启动插件，且注册到
	 */
	@Override
	@CMbeanMethod(description = "MonitorContainer start", impact = MBeanOperationInfo.INFO)
	public void start() {
		super.start();

		// 按排好的序启动所有的插件
		for (CmConsumer cplugin : pluginChain.getCmConsumers()) {
			cplugin.start();
			if (logger.isInfoEnabled()) {
				logger.info("Register cache:" + cplugin.getCacheId());
			}
			if (cplugin.isNeedCache()) {
				// 缓存区注册mbean
				CmCache<Serializable> cmCache = cacheMuster.getCmCache(cplugin
						.getCacheId());
				// 为防止重复，这里使用cacheid为mbean name
				MBeanAnnotationRegister.register(cmCache, cplugin.getCacheId());
			}
		}

		jobScheduler.start();
		MBeanAnnotationRegister.register(this);
	}

	@Override
	@CMbeanMethod(description = "MonitorContainer stop", impact = MBeanOperationInfo.INFO)
	public void stop() {
		super.stop();
		jobScheduler.stop();
		// 按排好的序停止所有的插件
		for (CmConsumer cplugin : pluginChain.getCmConsumers()) {
			cplugin.stop();
		}

	}

	@Override
	@CMbeanMethod(description = "MonitorContainer destory", impact = MBeanOperationInfo.INFO)
	public void destory() {
		super.destory();
		jobScheduler.destory();
		pluginChain.clear();
		// 按排好的序销毁所有的插件
		for (CmConsumer plugin : pluginChain.getCmConsumers()) {
			plugin.destory();
			try {
				jobScheduler.unRegisterPlugin(plugin);
			} catch (Exception e) {
				logger.error(MessageFormat.format(
						"Plugin destory exception , {0}", e.getMessage()), e);
				// continue
			}
		}
		MBeanAnnotationRegister.unRegister(this);
	}

	/**
	 * 获取插件
	 * 
	 * @param plugin
	 * @return
	 */
	@CMbeanMethod(description = "MonitorContainer getPlugin", impact = MBeanOperationInfo.INFO)
	public CmConsumer getPlugin(String pluginId) {
		if (pluginChain != null && StringUtils.isNotBlank(pluginId)) {
			for (CmConsumer plugin : pluginChain.getCmConsumers()) {
				if (plugin.getConsumerId().equals(pluginId)) {
					return plugin;
				}
			}
		}
		return null;
	}

	/**
	 * 获取插件
	 * 
	 * @param plugin
	 * @return
	 */
	@CMbeanMethod(description = "MonitorContainer getPlugin", impact = MBeanOperationInfo.INFO)
	public CmConsumer[] getPlugin(Class clazz) {
		if (pluginChain != null && clazz != null) {
			return pluginChain.getCmConsumer(clazz);
		}
		return null;
	}

	/**
	 * 获取所有插件
	 * 
	 * @param plugin
	 * @return
	 */
	@CMbeanMethod(description = "MonitorContainer getAllPlugin", impact = MBeanOperationInfo.INFO)
	public List<CmConsumer> getAllPlugin() {
		if (pluginChain != null) {
			return new ArrayList(pluginChain.getCmConsumers());
		}
		return null;
	}

	/**
	 * 获取缓存
	 * 
	 * @param key
	 * @return
	 */
	@CMbeanMethod(description = "MonitorContainer getCache", impact = MBeanOperationInfo.INFO)
	public CmCache<Serializable> getCache(String key) {
		if (cacheMuster == null) {
			return null;
		}
		return cacheMuster.getCmCache(key);
	}

	/**
	 * 获取缓存集合
	 * 
	 * @return
	 */
	@CMbeanMethod(description = "MonitorContainer getCmCacheMuster", impact = MBeanOperationInfo.INFO)
	public CmCacheMuster<String, Serializable> getCmCacheMuster() {
		if (cacheMuster == null) {
			return null;
		}
		return cacheMuster;
	}

	/**
	 * 获取插件容器
	 * 
	 * @return
	 * @throws DragonFlyException
	 */
	public static MonitorContainer getContainer() throws DragonFlyException {
		synchronized (MonitorContainer.class) {
			if (container == null) {
				container = new MonitorContainer();
			}
		}
		return container;
	}
}
